Plotly

Why use interactive graphics?

  • Zooming
  • Hovering
  • Sliding
  • Filtering

Difference between interactive and animated graphs

  • interactive graphs allow the user to manipulate different features of the graph

plotly Resources

library(plyr) # https://cran.r-project.org/web/packages/plyr/index.html
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.3     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::arrange()   masks plyr::arrange()
## ✖ purrr::compact()   masks plyr::compact()
## ✖ dplyr::count()     masks plyr::count()
## ✖ dplyr::desc()      masks plyr::desc()
## ✖ dplyr::failwith()  masks plyr::failwith()
## ✖ dplyr::filter()    masks stats::filter()
## ✖ dplyr::id()        masks plyr::id()
## ✖ dplyr::lag()       masks stats::lag()
## ✖ dplyr::mutate()    masks plyr::mutate()
## ✖ dplyr::rename()    masks plyr::rename()
## ✖ dplyr::summarise() masks plyr::summarise()
## ✖ dplyr::summarize() masks plyr::summarize()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly) # (https://plotly.com/)
## 
## Attaching package: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following objects are masked from 'package:plyr':
## 
##     arrange, mutate, rename, summarise
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
# read in 'wine.csv' data
wine <- read.csv('wine.csv')

head(wine)
##   Type Alcohol Malic  Ash Alcalinity Magnesium Phenols Flavanoids Nonflavanoids
## 1    1   14.23  1.71 2.43       15.6       127    2.80       3.06          0.28
## 2    1   13.20  1.78 2.14       11.2       100    2.65       2.76          0.26
## 3    1   13.16  2.36 2.67       18.6       101    2.80       3.24          0.30
## 4    1   14.37  1.95 2.50       16.8       113    3.85       3.49          0.24
## 5    1   13.24  2.59 2.87       21.0       118    2.80       2.69          0.39
## 6    1   14.20  1.76 2.45       15.2       112    3.27       3.39          0.34
##   Proanthocyanins Color  Hue Dilution Proline
## 1            2.29  5.64 1.04     3.92    1065
## 2            1.28  4.38 1.05     3.40    1050
## 3            2.81  5.68 1.03     3.17    1185
## 4            2.18  7.80 0.86     3.45    1480
## 5            1.82  4.32 1.04     2.93     735
## 6            1.97  6.75 1.05     2.85    1450
wine$Type <- as.factor(wine$Type)

Convert Static Graphs to Interactive Graphs Using ggplotly

Let’s look at a static graph comparing flavanoids to proline

static_plot <- wine %>%
  ggplot(aes(x = Flavanoids, y = Proline, color = Type)) +
  geom_point() +
  theme_minimal() +
  scale_color_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))

static_plot

How to create a plotly object

  • There are two main approaches to initialize a plotly object:

    • transforming a ggplot2 object with ggplotly()
    • setting up aesthetics mappings with plot_ly() directly
      • Use ggplot style attribute to subset the data (can be harder to control attributes)
      • Manually subset data for each trace (maximum control of attributes)

Today’s focus ggplotly()

# Create an interactive plot of Flavonoids vs Proline

ggplotly(static_plot)

Notes

toolbar from left to right are as follows:

Downloading the plot as a png file. Zoom Panning across the map. Selecting all points using a box. Selecting all points using a lasso. Zooming in and out on our plots. Resetting the view. data

Interactive plots are great!
Bad Design = Bad Interactive Plots
Follow data-viz best practices

Bar Plot

g <- ggplot(data = wine, aes(x = Type, fill = Type)) + 
     geom_bar(fill = c("#00AFBB", "#E7B800", "#FC4E07")) +
     theme_classic() 

ggplotly(g)

If you want the bar in descending order

g.5 <- count(wine, Type) %>% 
       ggplot(aes(x = reorder(Type, -n), y = n)) +
       geom_bar(fill = c("#00AFBB", "#E7B800", "#FC4E07"), stat = 'identity') +
       theme_classic() +
       xlab('Type')
     
ggplotly(g.5)

Histogram

g2 <- ggplot(wine, aes(x = Flavanoids, fill = as.factor(Type))) + 
      geom_histogram(bins = 15, alpha = 0.6) +
      theme_minimal() 
      scale_fill_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))
## <ggproto object: Class ScaleDiscrete, Scale, gg>
##     aesthetics: fill
##     axis_order: function
##     break_info: function
##     break_positions: function
##     breaks: waiver
##     call: call
##     clone: function
##     dimension: function
##     drop: TRUE
##     expand: waiver
##     get_breaks: function
##     get_breaks_minor: function
##     get_labels: function
##     get_limits: function
##     guide: legend
##     is_discrete: function
##     is_empty: function
##     labels: waiver
##     limits: NULL
##     make_sec_title: function
##     make_title: function
##     map: function
##     map_df: function
##     n.breaks.cache: NULL
##     na.translate: TRUE
##     na.value: grey50
##     name: waiver
##     palette: function
##     palette.cache: NULL
##     position: left
##     range: environment
##     rescale: function
##     reset: function
##     scale_name: manual
##     train: function
##     train_df: function
##     transform: function
##     transform_df: function
##     super:  <ggproto object: Class ScaleDiscrete, Scale, gg>
ggplotly(g2)

Scatterplot

g4 <- ggplot(wine, aes(x = Flavanoids, y = Proline, color = as.factor(Type))) + 
      geom_point() + 
      geom_smooth(method="loess", formula=y~x, se=F) + 
      scale_color_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"), name = 'Type') +
      theme_bw() 

ggplotly(g4)
# Flavonoids are rich in antioxidant
# A large percentage of the total amino acid left in the wine is in the form of proline

Creating interactive graphs directly in plot_ly

import plotly

library(plotly)

Bar plot

wine %>% 
  count(Type) %>% #using dplyr create frequency table
  plot_ly(x = ~Type, y = ~n) %>% # initialize graph in plotly, use ~ for aes mappings
  add_bars() %>% #set graph as bar chart
  layout(title = "Freq. of Wine Soil Type",
         xaxis = list(title = "Type"),
         yaxis = list(title = "Frequency"))

Reorder columns

wine %>% 
  count(Type) %>% #using dplyr create frequency table
  mutate(Type = fct_reorder(Type, n, .desc = TRUE)) %>% #order for largest to smallest
  plot_ly(x = ~Type, y = ~n) %>% # initialize graph in plotly, use ~ for aes mappings
  add_bars() %>% #set graph as bar chart
  layout(title = "Freq. of Wine Soil Type",
         xaxis = list(title = "Type"),
         yaxis = list(title = "Frequency"))

Basic Histogram

g6 <- wine %>% plot_ly(x = ~ Flavanoids, type = "histogram")

g6

Flavanoids by Type Histogram

Explanation!

# Lets split up the data to illustrate the manual way of making the plots
Type1 <- wine %>% filter(Type == 1)
Type2 <- wine %>% filter(Type == 2)
Type3 <- wine %>% filter(Type == 3)

# Full Manual method without for loop, subsetting data before
g7a <- plot_ly(alpha = 0.4) %>%
  add_histogram(x = ~Type1$Flavanoids, name = 'Type 1', opacity = 0.6, 
                marker = list(color = "#00AFBB",
                              alpha = 0.6,
                              line = list(color = "lightgray",
                              width = 2))) %>%
  add_histogram(x = ~Type2$Flavanoids, name = 'Type 2', opacity = 0.6,
                marker = list(color = "#E7B800",
                              line = list(color = "lightgray",
                              width = 2))) %>%
  add_histogram(x = ~Type3$Flavanoids, name = 'Type 3', opacity = 0.6,
                marker = list(color = "#FC4E07",
                              line = list(color = "lightgray",
                              width = 2))) %>%
  layout(barmode = 'overlay',
         title = 'Histogram of flavanoids by soil type',
         xaxis = list(title = 'flavanoids',
                      zeroline = FALSE),
         yaxis = list(title = 'count'))

g7a

Explanation!

# Manual method with for-loop that temp subsets data by soil type on the fly
my_colors <- c("#00AFBB","#E7B800","#FC4E07")
g7b <- wine %>% 
  plot_ly() # initialize graph in plotly, use ~ for aes mappings

  for (n in 1:(length(levels(wine$Type)))) {
    temp <- subset(wine, Type == levels(wine$Type)[n])

    g7b <-  add_histogram(g7b, data = temp, x = ~Flavanoids, name = paste0("Type ", n), 
                          opacity = 0.6, marker = list(color = my_colors[n], line = list(color = "lightgray",
                              width = 2)))
  }
 g7b <- g7b %>% layout(barmode = 'overlay',
         title = 'Histogram of flavanoids by soil type',
         xaxis = list(title = 'flavanoids',
                      zeroline = FALSE),
         yaxis = list(title = 'count'))
g7b

Explanation!

# Automated method, ggplot style
g7c <- wine %>% 
  # initialize graph in plotly, use ~ for aes mappings
  plot_ly(x = ~Flavanoids, color = ~Type, colors = c("#00AFBB","#E7B800","#FC4E07")) %>% 
  
 add_histogram(opacity = 0.6, marker = list(line = list(color = "lightgray", width = 2))) %>%
  
 layout(barmode = 'overlay',
         title = 'Histogram of flavanoids by soil type',
         xaxis = list(title = 'flavanoids',
                      zeroline = FALSE),
         yaxis = list(title = 'count'))
g7c

Scatter plot

Explanation!

# Manual subset method with more control for formatting
# Using dataframe subsets Type1, Type2, Type3 we generated earlier
g8a <- plot_ly(type = 'scatter', mode = 'markers')  %>%
  add_trace(x = Type1$Flavanoids,y = Type1$Proline,opacity = 0.5, 
      marker = list(color = "#00AFBB", size = 7,line = list(color = 'lightgray',
        width = .5)),name = 'Type 1') %>%
  
  add_trace(x = Type2$Flavanoids,y = Type2$Proline,
    marker = list( color = "#E7B800", size = 7,line = list(color = 'lightgray',
        width = .5)), name = 'Type 2')  %>%
  
  add_trace(x = Type3$Flavanoids, y = Type3$Proline, 
      marker = list(color = "#FC4E07",size = 7, line = list(color = 'lightgray',
        width = .5)), name = 'Type 3') %>%
  
  layout(title = 'Scatterplot of Flavanoids & Proline',
         xaxis = list(title = 'flavanoids',
                      zeroline = FALSE),
         yaxis = list(title = 'proline'))
g8a

Explanation!

# Automated method, ggplot style
g8b <- wine %>% 
  plot_ly(x = ~Flavanoids, y = ~Proline, color = ~Type, colors = c("#00AFBB", "#E7B800", "#FC4E07"),
          type = 'scatter', mode = 'markers') %>%  # initialize graph in plotly, use ~ for aes mappings
 layout(title = 'Scatterplot of Flavanoids & Proline',
         xaxis = list(title = 'flavanoids',
                      zeroline = FALSE),
         yaxis = list(title = 'proline'))

g8b

3D Scatterplot

Explanation!

g9a <- plot_ly(type = 'scatter3d', mode = 'markers') 
g9a <- g9a %>%
  add_trace(x = Type1$Flavanoids, y = Type1$Proline, z = Type1$Alcalinity, opacity = 0.5, 
    marker = list( color = "#00AFBB", size = 7,
      line = list(color = 'lightgray', width = .5)), name = 'Type 1')  %>%
  
  add_trace( x = Type2$Flavanoids, y = Type2$Proline, z = Type2$Alcalinity,
    marker = list( color = "#E7B800", size = 7, 
                   line = list( color = 'lightgray',width = .5)),name = 'Type 2') %>%
  
  add_trace( x = Type3$Flavanoids, y = Type3$Proline, z = Type3$Alcalinity,
    marker = list( color = "#FC4E07", size = 7,
      line = list( color = 'lightgray', width = .5 )), name = 'Type 3') %>%
  
  layout(title = 'Scatterplot of Flavanoids, Proline & Alcalinity',
         scene = list(xaxis = list(title = "flavanoids"),
                      yaxis = list(title = "proline"),
                      zaxis = list(title = "alcalinity")))
g9a

Explanation!

g9b <- wine %>% plot_ly( opacity = 0.5, type = 'scatter3d', mode = 'markers') %>% 
  add_trace(x = ~Flavanoids, y = ~Proline, z = ~Alcalinity, color = ~Type,
            marker = list(size = 7,line = list(width = .5)))  %>%
  
  layout(title = 'Scatterplot of Flavanoids, Proline & Alcalinity',
         scene = list(xaxis = list(title = "flavanoids"),
                      yaxis = list(title = "proline"),
                      zaxis = list(title = "alcalinity")))
g9b

Line Plot

(From plotly examples)

Explanation!

# Obtain data from subset of tooth growth dataset
tg <- ddply(ToothGrowth, c("supp", "dose"), summarise, length=mean(len))


# Create plotly figure
g10 <- plot_ly(tg, x = ~dose, y = ~length, type = 'scatter', mode = 'lines', 
               linetype = ~supp, color = I('black'))  %>% 
  layout(title = 'The Effect of Vitamin C on Tooth Growth in Guinea Pigs by Supplement Type',
         xaxis = list(title = 'Dose in milligrams/day'),
         yaxis = list (title = 'Tooth length'))

g10